package com.ticket.system.service.impl;

import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.google.common.collect.Maps;
import com.ticket.common.constant.CacheConstants;
import com.ticket.common.constant.PerformConstants;
import com.ticket.common.constant.UserConstants;
import com.ticket.common.core.domain.model.LoginUser;
import com.ticket.common.core.redis.RedisCache;
import com.ticket.common.exception.ServiceException;
import com.ticket.common.utils.*;
import com.ticket.common.utils.sign.Base64;
import com.ticket.system.domain.YanchuEvaluate;
import com.ticket.system.domain.YanchuOrderDetail;
import com.ticket.system.domain.vo.OrderDetailVo;
import com.ticket.system.domain.vo.WatchRecordVo;
import com.ticket.system.mapper.*;
import com.ticket.system.service.IYanchuOrderDetailService;
import com.ticket.system.service.IYanchuScoreService;
import com.ticket.system.service.IYanchuSeatService;
import com.ticket.system.service.IYanchuSessionService;
import org.apache.commons.compress.utils.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 订单详情Service业务层处理
 *
 * @author ruoyi
 * @date 2023-09-26
 */
@Service
public class YanchuOrderDetailServiceImpl implements IYanchuOrderDetailService {
    private static final Logger logger = LoggerFactory.getLogger(YanchuOrderDetailServiceImpl.class);
    @Autowired
    private YanchuOrderDetailMapper yanchuOrderDetailMapper;

    @Autowired
    private YanchuSeatMapper yanchuSeatMapper;
    @Autowired
    private RedisCache redisCache;

    @Value("${qrcode.checkUrl}")
    private String qrcodeUrl;

    @Autowired
    private YanchuSessionMapper yanchuSessionMapper;
    @Autowired
    private YanchuCheckMapper yanchuCheckMapper;

    @Autowired
    private YanchuOrderMapper yanchuOrderMapper;
    @Value("${notifyUrl}")
    private String notifyUrl;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private IYanchuSeatService iYanchuSeatService;

    @Autowired
    private IYanchuScoreService iYanchuScoreService;

    @Autowired
    private IYanchuSessionService iYanchuSessionService;

    @Resource
    private QrConfig qrconig;

    @Autowired
    private YanchuEvaluateMapper evaluateMapper;

    /**
     * 查询订单详情
     *
     * @param id 订单详情主键
     * @return 订单详情
     */
    @Override
    public YanchuOrderDetail selectYanchuOrderDetailById(Long id) {
        return yanchuOrderDetailMapper.selectYanchuOrderDetailById(id);
    }

    /**
     * 查询订单详情
     *
     * @param ticketNo 票号
     * @return 订单详情
     */
    @Override
    public YanchuOrderDetail selectOrderDetailByTicketNo(String ticketNo) {
        return yanchuOrderDetailMapper.selectOrderDetailByTicketNo(ticketNo);
    }

    @Override
    public List<WatchRecordVo> myWatchRecord(Long userId, Long userinfoId,  String phonenumber) {
        List<WatchRecordVo> list = yanchuOrderDetailMapper.selectWatchRecord(userId,userinfoId,phonenumber);
        if(list.isEmpty()){
            return new ArrayList<>();
        }
        List<Long> orderIds = list.stream().map(v -> v.getOrderId()).collect(Collectors.toList());
        List<YanchuEvaluate> evaluates = evaluateMapper.getMyEvaluate(orderIds,userId);
        if(!evaluates.isEmpty()){
            evaluates.forEach(e -> {
                list.forEach(r -> {
                    if(e.getOrderId().equals(r.getOrderId())){
                        r.setEvaluate(e);
                    }
                });
            });
        }
        return list;
    }

    @Override
    public OrderDetailVo selectOrderDetailVoById(Long id) {
        YanchuOrderDetail detail = yanchuOrderDetailMapper.selectOrderDetailVoById(id);
        OrderDetailVo detailVo = new OrderDetailVo();
        String idNumber = detail.getUserInfoVo().getIdNumber();
        idNumber = StringUtils.mask(idNumber, "(?<=\\w{3})\\w(?=\\w{4})");
        detailVo.setIdNumber(idNumber);
        detailVo.setShowNumber(detail.getShowNumber());
        detailVo.setTicket(detail.getTicket());
        String name = detail.getUserInfoVo().getUserName();
        detailVo.setUserName(StringUtils.maskCn(name));
        detailVo.setPerformVo(detail.getPerformVo());
        return detailVo;
    }

    /**
     * 查询订单详情列表
     *
     * @param yanchuOrderDetail 订单详情
     * @return 订单详情
     */
    @Override
    public List<YanchuOrderDetail> selectYanchuOrderDetailList(YanchuOrderDetail yanchuOrderDetail) {
        return yanchuOrderDetailMapper.selectYanchuOrderDetailList(yanchuOrderDetail);
    }

    @Override
    public List<OrderDetailVo> selectOrderDetailVoList(Long sessionId,Integer status,String userName,Long orderId) {
        return yanchuOrderDetailMapper.selectOrderDetailVoList(sessionId,status,userName,orderId);
    }
    @Override
    public List<OrderDetailVo> selectOrderDetailCancelVoList(Long sessionId,Integer status,String userName) {
        return yanchuOrderDetailMapper.selectOrderDetailCancelVoList(sessionId,status,userName);
    }

    /**
     * 新增订单详情
     *
     * @param yanchuOrderDetail 订单详情
     * @return 结果
     */
    @Override
    public int insertYanchuOrderDetail(YanchuOrderDetail yanchuOrderDetail) {
        yanchuOrderDetail.setCreateTime(DateUtils.getNowDate());
        return yanchuOrderDetailMapper.insertYanchuOrderDetail(yanchuOrderDetail);
    }

    /**
     * 修改订单详情
     *
     * @param yanchuOrderDetail 订单详情
     * @return 结果
     */
    @Override
    public int updateYanchuOrderDetail(YanchuOrderDetail yanchuOrderDetail) {
        yanchuOrderDetail.setUpdateTime(DateUtils.getNowDate());
        return yanchuOrderDetailMapper.updateYanchuOrderDetail(yanchuOrderDetail);
    }

    /**
     * 批量删除订单详情
     *
     * @param ids 需要删除的订单详情主键
     * @return 结果
     */
    @Override
    public int deleteYanchuOrderDetailByIds(Long[] ids) {
        return yanchuOrderDetailMapper.deleteYanchuOrderDetailByIds(ids);
    }

    /**
     * 删除订单详情信息
     *
     * @param id 订单详情主键
     * @return 结果
     */
    @Override
    public int deleteYanchuOrderDetailById(Long id) {
        return yanchuOrderDetailMapper.deleteYanchuOrderDetailById(id);
    }

    /**
     * 生成二维码
     *
     * @param detailId
     * @return
     */
    @Override
    public String createScanQrcode(Long detailId) {
        String png_base = null;
        BufferedImage img = null;
        ByteArrayOutputStream baos = null;
        try {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            logger.info("createScanQrcode userId:{} detailId:{}", loginUser.getUser().getUserId(), detailId);
            String detailKey = CacheConstants.TICKET_CHECK_DETAILID_KEY + detailId;
            Long snowId = redisCache.getCacheObject(detailKey);
            if(null == snowId){
                YanchuOrderDetail detail = yanchuOrderDetailMapper.selectYanchuOrderDetailById(detailId);
                if (null == detail) {
                    throw new ServiceException("获取订单信息失败！");
                }
//                if (!detail.getStatus().equals(PerformConstants.ORDER_PAY) && !detail.getStatus().equals(PerformConstants.ORDER_CHECKED)) {
//                    throw new ServiceException("订单状态不正确！");
//                }
                snowId = SnowFlakeUtil.getDefaultSnowFlakeId();
                redisCache.setCacheObject(CacheConstants.TICKET_CHECK_KEY + snowId, detail, 30, TimeUnit.DAYS);
                redisCache.setCacheObject(detailKey, snowId, 365, TimeUnit.DAYS);
            }

            String content = qrcodeUrl + snowId;
            logger.info("createScanQrcode detailId:{} content:{}", detailId, content);

            img = QrCodeUtil.generate(content, qrconig);
            baos = new ByteArrayOutputStream();
            ImageIO.write(img,"png",baos);
            png_base = Base64.encode(baos.toByteArray()).trim();
            png_base = png_base.replaceAll("\n","").replaceAll("\r","");
        }catch (Exception e){
            logger.error("createScanQrcode error",e);
        }finally {
            img = null;
            try {
                if (null != baos) {
                    baos.close();
                }
            }catch (Exception e){
                logger.error("close error",e);
            }
        }
        return png_base;
    }

    /**
     * 扫码验票
     *
     * @param code
     * @param userId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int ticketCheck(String code, Long userId,Long sessionId) {
        logger.info("ticketCheck code:{} userId:{} sessionId:{}", code, userId,sessionId);
        String keyChecked = CacheConstants.TICKET_CHECK_KEY + code;
        YanchuOrderDetail detail = redisCache.getCacheObject(keyChecked);
        if(null != detail){
            detail = this.selectOrderDetailByTicketNo(detail.getTicket());
        }
        if (null == detail) {
            throw new ServiceException("门票不存在，请出示正确的电子票二维码或票号");
        }
        if(null != sessionId && !detail.getSessionId().equals(sessionId)){
            throw new ServiceException("非当前场次门票，不可入场");
        }
        return ticketCheck(detail,userId,sessionId);
    }

    /**
     * 票号验票
     *
     * @param ticketNo
     * @param userId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int ticketNoCheck(String ticketNo,Long userId,Long sessionId) {
        logger.info("ticketNoCheck ticketNo:{} userId:{}", ticketNo, userId);
        YanchuOrderDetail detail = this.selectOrderDetailByTicketNo(ticketNo);
        if (null == detail) {
            throw new ServiceException("门票不存在");
        }
        if(null != sessionId && !detail.getSessionId().equals(sessionId)){
            throw new ServiceException("非当前场次");
        }
        return ticketCheck(detail,userId,sessionId);
    }

    @Transactional(rollbackFor = Exception.class)
    public int ticketCheck(YanchuOrderDetail detail,Long userId,Long sessionId){
        if(detail.getStatus().equals(PerformConstants.ORDER_CHECKED)){
            throw new ServiceException("门票已核验");
        }
        if(detail.getStatus().equals(PerformConstants.ORDER_PASTED)
                || detail.getStatus().equals(PerformConstants.ORDER_REFUND)
                || detail.getStatus().equals(PerformConstants.ORDER_REFUNDING)){
            throw new ServiceException("门票已作废");
        }
        if(null != detail.getDays() && detail.getDays() < 0){
            throw new ServiceException("该票号对应的场次尚未开始");
        }
        if(!detail.getStatus().equals(PerformConstants.ORDER_PAY)){
            throw new ServiceException("当前票号状态异常:"+detail.getTicket());
        }
        int count = yanchuOrderDetailMapper.updateById(detail.getId(), userId, PerformConstants.ORDER_CHECKED,
                PerformConstants.ORDER_PAY);
        if (count <= 0) {
            throw new ServiceException("验票修改状态失败");
        }
        YanchuOrderDetail detailQuery = new YanchuOrderDetail();
        detailQuery.setOrderId(detail.getOrderId());
        detailQuery.setStatus(PerformConstants.ORDER_PAY);
        List<YanchuOrderDetail> details = yanchuOrderDetailMapper.selectYanchuOrderDetailList(detailQuery);
        //修改订单状态为已核验
        if(CollectionUtils.isEmpty(details)){
            yanchuOrderMapper.updateExpireOrder(detail.getOrderId(),PerformConstants.ORDER_CHECKED,PerformConstants.ORDER_PAY);
        }
        List<String> tickets = Lists.newArrayList();
        tickets.add(detail.getTicket());
        int ticketCount = yanchuSeatMapper.updateSeat(tickets, PerformConstants.TICKET_SEAT_CHECKED, PerformConstants.TICKET_SEAT_PAY);
        if (ticketCount <= 0) {
            throw new ServiceException("验票修改座位状态失败");
        }

        String checkCountKey = CacheConstants.TICKET_CHECK_COUNT_KEY+userId+":"+DateUtils.dateTime();
        if(redisCache.hasKey(checkCountKey)){
            Integer value = redisCache.getCacheObject(checkCountKey);
            redisCache.setCacheObject(checkCountKey,value+1,1,TimeUnit.DAYS);
        }else{
            redisCache.incr(checkCountKey);
        }
        yanchuSessionMapper.updateChecked(count,detail.getSessionId());
        return count;
    }

    /**
     * 根据订单id查询订单详情
     *
     * @param orderId 订单id
     * @return
     */
    @Override
    public List<OrderDetailVo> selectOrderDetailByOrderId(Long orderId) {
        List<OrderDetailVo> orderDetailVoList = yanchuOrderDetailMapper.selectOrderDetailByOrderId(orderId);
        if (CollectionUtils.isEmpty(orderDetailVoList)) {
            return null;
        }
        //判断是否实名观演人，idNumber不等于null则需要对其数据处理
        for (OrderDetailVo orderDetailVo : orderDetailVoList) {
            if (!StringUtils.isEmpty(orderDetailVo.getIdNumber())) {
                if (orderDetailVo.getIdType() == UserConstants.ID_TYPE_IDENTITY_CARD) {
                    //身份证
                    orderDetailVo.setIdNumber(NumberReplaceUtils.idCardAddStar(orderDetailVo.getIdNumber()));
                } else if (orderDetailVo.getIdType() == UserConstants.ID_TYPE_PASSPORT) {
                    //护照
                    orderDetailVo.setIdNumber(NumberReplaceUtils.passportAddStar(orderDetailVo.getIdNumber()));
                }
            }
        }
        return orderDetailVoList;
    }

    @Override
    public Map<String,Integer> ticketCheckStat(Long userId){
        Map<String,Integer> map = Maps.newHashMap();
        String checkCountKey = CacheConstants.TICKET_CHECK_COUNT_KEY+userId+":"+DateUtils.dateTime();
        Integer count = redisCache.getCacheObject(checkCountKey);
        map.put("today",count);
        Integer checkedCount = yanchuOrderDetailMapper.checkedCount(userId);
        map.put("checkedCount",checkedCount);
        return map;
    }

    /**
     * 核验记录
     *
     * @param sessionId
     * @param keyName
     * @param userId
     * @param state
     * @return
     */
    @Override
    public List<YanchuOrderDetail> tickerVerification(Long sessionId, String keyName, Long userId, Integer state) {
        List<YanchuOrderDetail> details = yanchuOrderDetailMapper.tickerVerification(sessionId, keyName, userId, state);
        if (!CollectionUtils.isEmpty(details)){
            details.forEach(d -> d.setUserinfoIdNumber(NumberReplaceUtils.idCardAddStar(d.getUserinfoIdNumber())));
        }
        return details;
    }
}
